#include "Thread.h"
#include "RaytracerApp.h"
#include "AssetManager.h"
#include "Polygon.h"

#include "Scene.h"
#include "Sphere.h"
#include "PlanePrim.h"
#include "Vector.h"
#include "Light.h"
#include "Material.h"
#include "Texture.h"

#include "Camera.h"

#include "Image.h"

#include <boost/timer.hpp>
#include <stdio.h>

RaytracerApp RaytracerApp::m_Instance;

RaytracerApp::RaytracerApp()
{
} // Constructeur

RaytracerApp::~RaytracerApp()
{
	if (m_ThreadManager != NULL) {
		delete m_ThreadManager;
		m_ThreadManager = NULL;
	}

	if (m_Raytracer != NULL) {
		delete m_Raytracer;
		m_Raytracer = NULL;
	}
} // Desctructor

RaytracerApp* RaytracerApp::getInstance()
{
	return &m_Instance;
} // getInstance

void RaytracerApp::init(std::string configPath)
{
	m_ConfigPath = configPath;

	ConfigFile pFile(m_ConfigPath);
	m_Raytracer = new Raytracer(pFile);
	Scene *pScene = new Scene(pFile);

	m_Raytracer->setScene(pScene);

	m_ThreadManager = new ThreadManager(pScene);
	m_ThreadManager->createBitfield(m_Raytracer->getXOffset(), m_Raytracer->getYOffset());
}

Image* RaytracerApp::run()
{
	m_ThreadManager->start(m_Raytracer);

	// RETOURNE SEULEMENT UNE IMAGE!
	return m_Raytracer->computeImg();
} // run

void RaytracerApp::save(Image *img)
{
	if (!img->save("img.png"))
		getchar();

	if (m_Raytracer->getSamplingFactor() != 1) {
		if (!img->resampleByFactor(1).save("rimg.png"))
			getchar();
	}
}

void RaytracerApp::update(int key, float delta)
{
	switch (key) 
	{
		case 119:		// W key
			m_Raytracer->getCamera()->walk(100.0f*delta);
			break;
		case 115:		// S key
			m_Raytracer->getCamera()->walk(-100.0f*delta);
			break;
		case 97:		// A key
			m_Raytracer->getCamera()->strafe(-100.0f*delta);
			break;
		case 100:		// D key
			m_Raytracer->getCamera()->strafe(100.0f*delta);
			break;
		case 291:		// Left arrow
			m_Raytracer->getCamera()->yaw(-20.0f*delta);
			break;
		case 292:		// Right arrow
			m_Raytracer->getCamera()->yaw(20.0f*delta);
			break;
		case 293:		// Up arrow
			m_Raytracer->getCamera()->pitch(20.0f*delta);
			break;
		case 294:		// Down arrow
			m_Raytracer->getCamera()->pitch(-20.0f*delta);
			break;
	}
	m_Raytracer->getCamera()->update();
}
